'''
The parser for property of pi-graph.

Created on Mar 11, 2014

@author: vietphv
'''
from ast import ASTNode
import lex
import yacc

reserved = ()

tokens = reserved + ('NAME',  # name
                     'NUM',  # number
                     'LPAR',  # left parentheses
                     'RPAR',  # right parentheses
                     'COMMA',  # comma
                     'SEMI',  # semicolon
                     'ALL',  # universal operator
                     'ANY',  # exists operator
                     'ANYv',  # exists a vertex V
                     'ANYn',  # exists a name N
                     'INV')  # inverse operator

# Complex tokens
def t_NAME(t):
    '[a-zA-Z_][a-zA-Z0-9_]*'
    if t.value in reserved:
        t.type = t.value
    return t

def t_NUM(t):
    r'\d+'
    t.value = int(t.value)
    return t

def t_ANYv(t):
    '[?]\d+'
    s = t.value
    t.value = int(s[1:])
    return t
    
def t_ANYn(t):
    '[?][a-zA-Z_][a-zA-Z0-9_]*'
    s = t.value
    t.value = s[1:]
    return t

def t_error(t):
    print "Illegal character '%s'" % t.value[0]
    t.lexer.skip(1)

# Simple tokens
t_ignore = ' \t\n'
t_LPAR = '\('
t_RPAR = '\)'
t_COMMA = ','
t_SEMI = ';'
t_ALL = '\*'
t_ANY = '\?'
t_INV = '!'


start = 'local_prop'  # initial point

def p_local_prop(p):
    '''local_prop : derivation predicate
                  | INV local_prop'''
    if p[1] == "!":
        p[0] = ASTNode('prop1', [p[2]])
    else:
        p[0] = ASTNode('prop0', [p[1], p[2]])

def p_predicate(p):
    '''predicate : NAME LPAR parameters RPAR
                 | NAME LPAR parameters SEMI parameters RPAR'''
    if len(p) == 5:
        p[0] = ASTNode('pred1', [p[1], p[3]])
    else:
        p[0] = ASTNode('pred2', [p[1], p[3], p[5]])
        
def p_derivation(p):
    '''derivation : empty
                  | ALL derivation
                  | ANY derivation
                  | ANYn derivation
                  | ANYv derivation'''
    if len(p) == 2:
        p[0] = ASTNode('drv0')
    else:
        p[0] = ASTNode('drv1', [p[1], p[2]])

def p_parameters(p):
    '''parameters : empty
                  | NAME parameters
                  | NUM parameters
                  | NAME COMMA parameters
                  | NUM COMMA parameters'''
    if len(p) == 2 or len(p) == 3:
        if p[1] == None:
            p[0] = ASTNode('param0')  # empty
        else:
            p[0] = ASTNode('param1', [p[1]])
    else:
        p[0] = ASTNode('paramx', [p[1], p[3]])
        
def p_empty(p):
    '''empty :'''
    pass

def p_error(p):
    raise SyntaxError(p)


ProLexer = lex.lex()
ProParser = yacc.yacc(method='LALR',
                      debug=1,
                      module=None,
                      tabmodule='proparsertab',
                      start=None,
                      check_recursion=1,
                      optimize=0,
                      write_tables=1,
                      debugfile='proparser.out',
                      outputdir='',
                      debuglog=None,
                      errorlog=None,
                      picklefile=None)
